package com.corpgovernment.organization.service.impl;

import com.corpgovernment.api.messageadvice.enums.MsgBizType;
import com.corpgovernment.api.ordercenter.enums.SourceTypeEnums;
import com.corpgovernment.api.organization.dto.EmployeeOpenCardReq;
import com.corpgovernment.api.organization.dto.GetEmployeeOpenCardReq;
import com.corpgovernment.api.organization.dto.GetEmployeeOpenCardRsp;
import com.corpgovernment.api.organization.enums.UserOrgRelationStatusEnum;
import com.corpgovernment.common.apollo.OrganizationApollo;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.common.utils.HttpUtils;
import com.corpgovernment.common.utils.LogSplicingUtils;
import com.corpgovernment.organization.Bo.CommonSupplierUrlBo;
import com.corpgovernment.organization.constant.CommonConst;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.corpgovernment.organization.dataloader.BasicDataClientLoader;
import com.corpgovernment.organization.dataloader.db.MbOrgEmployeeLoader;
import com.corpgovernment.organization.dataloader.db.MbSupplierCompanyLoader;
import com.corpgovernment.organization.dataloader.db.MbUserOrgRelationLoader;
import com.corpgovernment.organization.dto.BindAccountReq;
import com.corpgovernment.organization.dto.BindAccountRsp;
import com.corpgovernment.organization.dto.BindGetVerifyCodeReq;
import com.corpgovernment.organization.dto.BindGetVerifyCodeRsp;
import com.corpgovernment.organization.entity.db.MbOrgEmployeeInfo;
import com.corpgovernment.organization.entity.db.MbOrgEmployeeOpenCardRecord;
import com.corpgovernment.organization.entity.db.MbUserOrgRelation;
import com.corpgovernment.organization.event.EmployeeActionEvent;
import com.corpgovernment.organization.model.MbUserOrgRelationModel;
import com.corpgovernment.organization.model.SupplierCompanyModel;
import com.corpgovernment.organization.service.CTripAccountService;
import com.corpgovernment.organization.service.CtripOpenCardService;
import com.corpgovernment.organization.service.IUserOrgRelationService;
import com.corpgovernment.organization.service.MbOrgEmployeeOpenCardRecordService;
import com.corpgovernment.organization.service.MsgService;
import com.corpgovernment.organization.vo.BindCtripAccountReqVo;
import com.corpgovernment.organization.vo.BindCtripAccountRspVo;
import com.corpgovernment.organization.vo.BindGetVerifyCodeReqVo;
import com.corpgovernment.organization.vo.BindGetVerifyCodeRspVo;
import com.ctrip.corp.obt.generic.event.core.EventCenter;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CTripAccountServiceImpl implements CTripAccountService {

    @Autowired
    private OrganizationApollo organizationApollo;

    @Autowired
    private BasicDataClientLoader basicDataClientLoader;

    @Autowired
    private OrganizationEmployeeServiceImpl organizationEmployeeService;

    @Autowired
    private MbOrgEmployeeOpenCardRecordService orgEmployeeOpenCardRecordService;

    @Autowired
    private MbOrgEmployeeLoader mbOrgEmployeeLoader;

    @Autowired
    private IUserOrgRelationService userOrgRelationService;
    @Autowired
    private MsgService msgService;
    @Autowired
    private EventCenter eventCenter;
    @Autowired
    private MbSupplierCompanyLoader supplierCompanyLoader;
    @Autowired
    private MbUserOrgRelationLoader mbUserOrgRelationLoader;
    @Autowired
    private CtripOpenCardService ctripOpenCardService;

    @Override
    public BindGetVerifyCodeRspVo getVerifyCode(BindGetVerifyCodeReqVo request) {
        StringBuilder logContext = new StringBuilder();
        try {
            LogSplicingUtils.addLogContext(logContext,"绑定携程账号获取验证码入参：%s", JsonUtils.toJsonString(request));
            MbUserOrgRelationModel mbUserOrgRelationModel = mbUserOrgRelationLoader.getRelationByUid(request.getUid());
            if (mbUserOrgRelationModel == null){
                throw new CorpBusinessException(OrganizationResponseCodeEnum.COMPANY_ACCOUNT_UID_CONFIG_ERROR);
            }
            List<SupplierCompanyModel> companyConfigList =
                    ctripOpenCardService.getParentConfig(mbUserOrgRelationModel.getOrgId());
            if (CollectionUtils.isEmpty(companyConfigList)){
                throw new CorpBusinessException(OrganizationResponseCodeEnum.COMPANY_ACCOUNT_CONFIG_EMPTY);
            }
            SupplierCompanyModel companyConfig = companyConfigList.get(0);

            //获取请求地址
            CommonSupplierUrlBo commonUrl = CommonSupplierUrlBo.getCommonSupplierUrl(organizationApollo.getCtripUrl(),
                    companyConfig.getSupplierCorpId(),
                    companyConfig.getSubAccountCode(),
                    logContext);
            if (Objects.isNull(commonUrl) || Objects.isNull(commonUrl.getGetBindVerifyCode())){
                return BindGetVerifyCodeRspVo.failed("500", "请联系管理员启用该功能");
            }
            if (StringUtils.isBlank(request.getUid())){
                return BindGetVerifyCodeRspVo.failed("500", "缺少必要性参数[uid]无法操作绑定功能");
            }
            if (StringUtils.isBlank(request.getMobilePhone())){
                return BindGetVerifyCodeRspVo.failed("500", "缺少必要性参数[mobilePhone]无法操作绑定功能");
            }

            MbOrgEmployeeOpenCardRecord mbOrgEmployeeOpenCardRecord = orgEmployeeOpenCardRecordService.selectByUid(request.getUid());
            if (Objects.isNull(mbOrgEmployeeOpenCardRecord)){
                return BindGetVerifyCodeRspVo.failed("500", "该账户未开通绑定携程账户权限");
            }

            CommonSupplierUrlBo.UrlInfo commonUrlGetBindVerifyCode = commonUrl.getGetBindVerifyCode();
            String ticket = basicDataClientLoader.ctripTokenByCorpID(commonUrlGetBindVerifyCode.getCorpId(), commonUrlGetBindVerifyCode.getSupplierCode());
            BindGetVerifyCodeReq bindGetVerifyCodeReq = new BindGetVerifyCodeReq();
            BindGetVerifyCodeReq.AuthInfo authInfo = new BindGetVerifyCodeReq.AuthInfo();
            authInfo.setAppKey(String.format("%s_%s", "obk", commonUrlGetBindVerifyCode.getCorpId()));
            authInfo.setTicket(ticket);
            bindGetVerifyCodeReq.setAuth(authInfo);
            bindGetVerifyCodeReq.setCorpId(commonUrlGetBindVerifyCode.getCorpId());
            bindGetVerifyCodeReq.setMobilePhone(request.getMobilePhone());
            bindGetVerifyCodeReq.setEmployeeId(mbOrgEmployeeOpenCardRecord.getOpenCardUid());
            bindGetVerifyCodeReq.setChannel(SourceTypeEnums.APP.getCode().equalsIgnoreCase(request.getSource()) ? "H5" : "PC");
            LogSplicingUtils.addLogContext(logContext,"req：%s", JsonUtils.toJsonString(bindGetVerifyCodeReq));
            String result = HttpUtils.doPostJSON(commonUrlGetBindVerifyCode.getSupplierCode(), "获取验证码", commonUrlGetBindVerifyCode.getUrl(), JsonUtils.toJsonString(bindGetVerifyCodeReq));
            LogSplicingUtils.addLogContext(logContext,"rsp：%s", result);
            BindGetVerifyCodeRsp bindGetVerifyCodeRsp = JsonUtils.parse(result, BindGetVerifyCodeRsp.class);
            if (Objects.isNull(bindGetVerifyCodeRsp) || Objects.isNull(bindGetVerifyCodeRsp.getStatus())){
                return BindGetVerifyCodeRspVo.failed();
            }
            BindGetVerifyCodeRsp.StatusInfo status = bindGetVerifyCodeRsp.getStatus();
            return BindGetVerifyCodeRspVo.success(status.getErrorCode(), status.getMessage());
        }catch (Exception e){
            log.error("{}", e);
            return BindGetVerifyCodeRspVo.failed();
        }finally {
            log.info("{}", logContext);
        }
    }

    @Override
    public BindCtripAccountRspVo bindAccount(BindCtripAccountReqVo request) {
        StringBuilder logContext = new StringBuilder();
        try {
            LogSplicingUtils.addLogContext(logContext,"绑定携程账号入参：%s", JsonUtils.toJsonString(request));
            MbUserOrgRelationModel mbUserOrgRelationModel = mbUserOrgRelationLoader.getRelationByUid(request.getUid());
            if (mbUserOrgRelationModel == null){
                throw new CorpBusinessException(OrganizationResponseCodeEnum.COMPANY_ACCOUNT_UID_CONFIG_ERROR);
            }
            List<SupplierCompanyModel> companyConfigList =
                    ctripOpenCardService.getParentConfig(mbUserOrgRelationModel.getOrgId());
            if (CollectionUtils.isEmpty(companyConfigList)){
                throw new CorpBusinessException(OrganizationResponseCodeEnum.COMPANY_ACCOUNT_CONFIG_EMPTY);
            }
            SupplierCompanyModel companyConfig = companyConfigList.get(0);

            //获取请求地址
            CommonSupplierUrlBo commonUrl = CommonSupplierUrlBo.getCommonSupplierUrl(organizationApollo.getCtripUrl(),
                    companyConfig.getSupplierCorpId(),
                    companyConfig.getSubAccountCode(),
                    logContext);
            if (Objects.isNull(commonUrl) || Objects.isNull(commonUrl.getBindAccount())){
                return BindCtripAccountRspVo.failed("500", "请联系管理员启用该功能");
            }
            if (StringUtils.isBlank(request.getUid())){
                return BindCtripAccountRspVo.failed("500", "缺少必要性参数[uid]无法操作绑定功能");
            }
            if (StringUtils.isBlank(request.getCountryCode())){
                request.setCountryCode("86");
            }
            if (StringUtils.isBlank(request.getMobilePhone())){
                return BindCtripAccountRspVo.failed("500", "缺少必要性参数[mobilePhone]无法操作绑定功能");
            }
            if (StringUtils.isBlank(request.getVerifyCode())){
                return BindCtripAccountRspVo.failed("500", "缺少必要性参数[verifyCode]无法操作绑定功能");
            }

            MbOrgEmployeeOpenCardRecord mbOrgEmployeeOpenCardRecord = orgEmployeeOpenCardRecordService.selectByUid(request.getUid());
            if (Objects.isNull(mbOrgEmployeeOpenCardRecord)){
                return BindCtripAccountRspVo.failed("500", "该账户未开通绑定携程账户权限");
            }

            CommonSupplierUrlBo.UrlInfo commonUrlBindAccount = commonUrl.getBindAccount();
            String ticket = basicDataClientLoader.ctripTokenByCorpID(commonUrlBindAccount.getCorpId(), commonUrlBindAccount.getSupplierCode());
            BindAccountReq bindAccountReq = new BindAccountReq();
            BindAccountReq.AuthInfo authInfo = new BindAccountReq.AuthInfo();
            authInfo.setAppKey(String.format("%s_%s", "obk", commonUrlBindAccount.getCorpId()));
            authInfo.setTicket(ticket);
            bindAccountReq.setAuth(authInfo);
            bindAccountReq.setCorpId(commonUrlBindAccount.getCorpId());
            bindAccountReq.setPersonAccount(request.getMobilePhone());
            bindAccountReq.setEmployeeId(mbOrgEmployeeOpenCardRecord.getOpenCardUid());
            bindAccountReq.setCountryCode(request.getCountryCode().replace("+", ""));
            bindAccountReq.setVerifyCode(request.getVerifyCode());
            LogSplicingUtils.addLogContext(logContext,"req：%s", JsonUtils.toJsonString(bindAccountReq));
            String result = HttpUtils.doPostJSON(commonUrlBindAccount.getSupplierCode(), "绑定携程账号", commonUrlBindAccount.getUrl(), JsonUtils.toJsonString(bindAccountReq));
            LogSplicingUtils.addLogContext(logContext,"rsp：%s", result);
            BindAccountRsp bindAccountRsp = JsonUtils.parse(result, BindAccountRsp.class);
            if (Objects.isNull(bindAccountRsp) || Objects.isNull(bindAccountRsp.getStatus())){
                return BindCtripAccountRspVo.failed();
            }
            BindAccountRsp.StatusInfo status = bindAccountRsp.getStatus();

            //0:成功,10240007:已经绑定账号
            if ("0".equals(status.getErrorCode()) || "10240007".equals(status.getErrorCode())) {
                MbOrgEmployeeInfo mbOrgEmployeeInfo = new MbOrgEmployeeInfo();
                mbOrgEmployeeInfo.setUid(request.getUid());
                mbOrgEmployeeInfo.setIsBindCtripAccount(true);
                organizationEmployeeService.update(mbOrgEmployeeInfo);

                Map<String, Object> vars = new HashMap<>();
                vars.put("CTripPhoneNo",request.getMobilePhone());
                msgService.sendAliyunTemplateMsg(MsgBizType.USER_BIND_CTRIP_ACCOUNT,vars,request.getMobilePhone(),request.getCountryCode());
            }

            if ("10240008".equals(status.getErrorCode())) {
                //散户异常30003 -> 未注册携程账号
                if (status.getMessage().indexOf("30003") > -1){
                    return BindCtripAccountRspVo.success(status.getErrorCode(), "绑定账号失败,请确认您的手机号码是否有注册过携程网账号", status.getMessage());
                }
                //散户异常60007 -> 绑定了商旅账号
                if (status.getMessage().indexOf("60007") > -1){
                    return BindCtripAccountRspVo.success(status.getErrorCode(), "绑定账号失败,请先在携程商旅解绑账号", status.getMessage());
                }
                //散户异常20011 -> 验证码无效
                if (status.getMessage().indexOf("20011") > -1){
                    return BindCtripAccountRspVo.success(status.getErrorCode(), "请获取新的验证码进行绑定", status.getMessage());
                }
            }
            return BindCtripAccountRspVo.success(status.getErrorCode(), status.getMessage());
        }catch (Exception e){
            log.error("{}", e);
            return BindCtripAccountRspVo.failed();
        }finally {
            log.info("{}", logContext);
        }
    }

    @Override
    public Boolean employeeOpenCard(EmployeeOpenCardReq request) {
        if (StringUtils.isNotBlank(request.getUid())){
            MbUserOrgRelationModel model = mbUserOrgRelationLoader.getRelationByUid(request.getUid());
            if (model == null){
                throw new CorpBusinessException(OrganizationResponseCodeEnum.COMPANY_ACCOUNT_UID_CONFIG_ERROR);
            }
            eventCenter.post(new EmployeeActionEvent(Lists.newArrayList(request.getUid()), model.getOrgId(), EmployeeActionEvent.OpenCardAction.ACTION_REDRESS));
        } else {
            List<MbOrgEmployeeOpenCardRecord> orgEmployeeOpenCardRecords = orgEmployeeOpenCardRecordService.selectALL();
            Map<String, MbOrgEmployeeOpenCardRecord> uidMap = orgEmployeeOpenCardRecords.stream().collect(Collectors.toMap(item -> item.getPlatUid(), Function.identity(), (k1, k2) -> k1));

            MbOrgEmployeeInfo orgEmployeeInfo = new MbOrgEmployeeInfo();
            orgEmployeeInfo.setDeleteTime(new Date(0));
            orgEmployeeInfo.setValid(CommonConst.TRUE);
            List<MbOrgEmployeeInfo> mbOrgEmployeeInfos = mbOrgEmployeeLoader.selectByRecord(orgEmployeeInfo);

            mbOrgEmployeeInfos.stream().forEach(item ->{
                MbOrgEmployeeOpenCardRecord orgEmployeeOpenCardRecord = uidMap.get(item.getUid());
                if (Objects.isNull(orgEmployeeOpenCardRecord)){
                    List<MbUserOrgRelation> userOrgRelations = userOrgRelationService.findByUid(item.getUid());
                    userOrgRelations = userOrgRelations.stream().filter(line ->
                            UserOrgRelationStatusEnum.NORMAL.getStatus().compareTo(line.getStatus()) == 0).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(userOrgRelations)){
                        eventCenter.post(new EmployeeActionEvent(Lists.newArrayList(item.getUid()), item.getOrgId(), EmployeeActionEvent.OpenCardAction.ACTION_REDRESS));
                    }
                }
            });
        }
        return true;
    }

    @Override
    public GetEmployeeOpenCardRsp getEmployeeOpenCardInfo(GetEmployeeOpenCardReq request) {
        MbOrgEmployeeOpenCardRecord mbOrgEmployeeOpenCardRecord = orgEmployeeOpenCardRecordService.selectByUid(request.getUid());
        MbOrgEmployeeInfo mbOrgEmployeeInfo = organizationEmployeeService.findAllByUid(request.getUid());

        GetEmployeeOpenCardRsp rsp = new GetEmployeeOpenCardRsp();
        if (Objects.nonNull(mbOrgEmployeeOpenCardRecord)){
            rsp.setPlatUid(mbOrgEmployeeOpenCardRecord.getPlatUid());
            rsp.setSupplierUid(mbOrgEmployeeOpenCardRecord.getSupplierUid());
        }
        rsp.setIsBindCtripAccount(Optional.ofNullable(mbOrgEmployeeInfo).map(MbOrgEmployeeInfo::getIsBindCtripAccount).orElse(false));

        return rsp;
    }

}